/**
 * Copyright (c) [2025] [何屹林]
 *
 * 保留所有权利。
 *
 * 文件名称：program.cpp
 * 模块功能说明：
 * 该模块实现了正则表达式产生的代码内容，将代码内容固定以便之后调用。
 *
 * 华南师范大学-计算机学院-网络工程-1班
 * 作者：何屹林-20222132023
 * 完成日期：2025年7月24日
 */
#include "logic.h"

void Logic::genHeader() {
    LexCode +=
        "#include <stdlib.h>\n"
        "#include <string.h>\n"
        "#include <stdbool.h>\n"
        "#include <stdint.h>\n"
        "#include <float.h>\n"
        "#include <stdio.h>\n"
        "#define MaxCd " + QString::number(CdCnt) + "\n"
                                   "int n, m;\n"
                                   "bool flag;\n"
                                   "char c, str[200];\n"
                                   "int curr[MaxCd], next[MaxCd];\n"
                                   "FILE* input, * output;\n";
}


void Logic::genmap()
{
    LexCode+="\n"+mapToString(token_makecd)+"\n";
}

void Logic::genState() {
    LexCode +=
        "struct State { int cd, pr; }\n"
        "S[] = {";
    int k = 0;
    for (auto& x : minDFA) {
        if (k++ % 10 == 0) LexCode += "\n\t";

        //ccdd.insert(Cd2Token[x->cd],2);
        LexCode += "{" + QString::number(x->endcd) + ", " + QString::number(ccdd[Cd2Token[x->cd]]) + "}, ";
        //LexCode += "{" + QString::number(x->cd) + ", " + QString::number(CdPrec[x->cd]) + "}, ";
    }
    LexCode.erase(LexCode.end() - 2, LexCode.end());
    LexCode += "\n};\n";
}


void Logic::genTools() {
    LexCode +=
        "void append() {\n"
        "\tsize_t len = strlen(str);\n"
        "\tstr[len] = c, str[len + 1] = '\\0';\n"
        "}\n"
        "int get_cd() {\n"
        "\tint cd = 0, pr = -1;\n"
        "\tfor (int i = 0; i < n; ++i)\n"
        "\t\tif (S[curr[i]].pr > pr)\n"
        "\t\t\tcd = S[curr[i]].cd, pr = S[curr[i]].pr;\n"
        "\treturn cd;\n"
        "}\n"
        "bool has_end(int id) {\n"
        "\tfor (int i = 0; i < n; ++i)\n"
        "\t\tif (curr[i] != id && S[curr[i]].cd > 0)\n"
        "\t\t\treturn true;\n"
        "\treturn false;\n"
        "}\n";
}

// //字符集合映射表(xxx=[a-zA-Z])
// QMap<QString,QSet<QChar>>CharSet;

void Logic::genIsCharSet() {
    //for (const auto& p : CharSet)
    for(auto p=CharSet.begin();p !=CharSet.end();++p)
    {
        auto v = sortCharSet(p.value());
        QString code0, code1;
        LexCode +=
            "bool is_" + p.key() + "() {\n"
                                   "\treturn";
        for (int i = 0; i < v[0].size(); i += 2)
            code0 += " (c >= \'" + escape(v[0][i]) + "\' && c <= \'" + escape(v[0][i + 1]) + "\') ||";
        if (!code0.isEmpty()) code0.erase(code0.end() - 3, code0.end());
        if (!v[1].empty()) {  // 单字符
            for (const auto& c : v[1])
                code1 += "|| c == \'" + escape(c) + "\' ";
            code1.chop(1);
        }
        if (code0.isEmpty()) code1.erase(code1.begin(), code1.begin() + 2);
        else if (!code1.isEmpty()) code0 += "\n\t\t";
        LexCode += code0, LexCode += code1;
        LexCode +=
            ";\n"
            "}\n";
    }
}



void Logic::genCores() {
    LexCode +=
        "void new_state() {\n"
        "\tstr[0] = '\\0';\n"
        "\tn = 1, curr[0] = " + QString::number(MDFAstart) + ";\n"
                                       "}\n"
                                       "void end_state() {\n"
                                       "\tint cd = get_cd();\n"
                                       "\tswitch (cd) {\n"
                                       "\tcase 0: return;\n";
    for (auto& x : MainCd[1])
        LexCode += "\tcase " + QString::number(x) + ": break;\n";
    for (auto& x : MainCd[0])
        LexCode += "\tcase " + QString::number(x) + ": fprintf(output, \"%d\\t%s\\n\", cd, str); break;\n";
    //\"%d\\t%s\\n\", cd, str
    //"\tdefault: fprintf(output, \"%d\\n\", cd);\n"
    LexCode +=
        //"\tdefault: fprintf(output, \"%d   %s\\n\", cd, str);\n"
        "\tdefault: fprintf(output, \"%d\\n\", cd);\n"
        "\t}\n"
        "\tungetc(c, input);\n"
        "\tn = 0;\n"
        "}\n"
        "bool next_state(int id) {\n"
        "\tint k = m, x = -1;\n"
        "\tswitch (id) {\n";
    for (auto& x : minDFA) {

        QString anyCode, setCode, charCode;
        //for (const auto& p : x->transfer)
        for(auto p=x->transfer.begin();p !=x->transfer.end();++p)
        {
            if (p.value() == -1) continue;
            QString m = QString::number(p.value());
            if (p.key() == ANY) {
                if (x->id == p.value()) anyCode += "\t\tif (has_end(id)) return false;\n";
                anyCode += "\t\tnext[m++] = " + m + ";\n";
            }
            else if (CharSetSym.find(p.key()) != CharSetSym.end())
                setCode += "\t\tif (is_" + C2S[p.key()] + "()) next[m++] = " + m + ";\n";
            else {
                if (charCode.isEmpty()) charCode += "\t\tswitch (c) {\n";
                QString n = C2S.find(p.key()) != C2S.end() ? trim(C2S[p.key()]) : STR(p.key());
                charCode += "\t\tcase '" + n + "': next[m++] = " + m + "; break;\n";
            }
        }
        if (!anyCode.isEmpty() || !setCode.isEmpty() || !charCode.isEmpty()) {
            if (!charCode.isEmpty()) charCode += "\t\t}\n";
            LexCode += "\tcase " + QString::number(x->id) + ":\n";
            LexCode += anyCode, LexCode += setCode, LexCode += charCode;
            LexCode += "\t\tbreak;\n";
        }
    }
    LexCode +=
        "\t}\n"
        "\treturn k != m;\n"
        "}\n";
}


void Logic::genMain() {
    LexCode +=
        "void coding() {\n"
        "\twhile (c = fgetc(input)) {\n"
        "\t\tif (n == 0) new_state();\n"
        "\t\tm = 0, flag = false;\n"
        "\t\tfor (int i = 0; i < n; ++i)\n"
        "\t\t\tflag |= next_state(curr[i]);\n"
        "\t\tflag ? append() : end_state();\n"
        "\t\tn = m;\n"
        "\t\tfor (int i = 0; i < n; ++i)\n"
        "\t\t\tcurr[i] = next[i];\n"
        "\t\tif (c == EOF) break;\n"
        "\t}\n"
        "\tfprintf(output, \"0\");\n"
        "}\n"
        "int main(int argc, char* argv[]) {\n"
        "\tif (argc < 3) exit(1);\n"
        "\tinput = fopen(argv[1], \"r\");\n"
        "\tif (input == NULL) {\n"
        "\t\tprintf(\"Failed to open input file\");\n"
        "\t\texit(1);\n"
        "\t}\n"
        "\toutput = fopen(argv[2], \"w\");\n"
        "\tif (output == NULL) {\n"
        "\t\tprintf(\"Failed to open output file\");\n"
        "\t\tfclose(input);\n"
        "\t\texit(1);\n"
        "\t}\n"
        "\tcoding();\n"
        "\tfclose(input);\n"
        "\tfclose(output);\n"
        "\treturn 0;\n"
        "}";
}

// 生成词法分析源程序
void Logic::genLexer() {
    genHeader();
    //qDebug()<<LexCode;
    //genmap();

    genState(), genTools();
    //qDebug()<<LexCode;
    genIsCharSet(), genCores(), genMain();
}
